﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Formatters;
using Microsoft.Net.Http.Headers;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json;
using System.Net.WebSockets;
using Microsoft.AspNet.Http;
using System.Text;
using System.Threading;
using System.Collections.Concurrent;

namespace ldhWebApiIIS
{
    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
            // Set up configuration sources.
            var builder = new ConfigurationBuilder()
                .AddJsonFile("appsettings.json")
                .AddEnvironmentVariables();
            Configuration = builder.Build();

            //var configurationSection = Configuration.GetSection("AppSettings");
            //var title = configurationSection.Get<string>("ApplicationTitle");
            database.BaseManager.ConString = Configuration.Get("AppSettings:mongo", "mongodb://localhost:27017");
            middleware.CheckIPMiddleware.IpWhitelist = Configuration.Get("AppSettings:IpWhitelist", "0.0.0.0/0").Split(',').ToList();
        }

        public IConfigurationRoot Configuration { get; set; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddMvc(options =>
            {
                //注册自定义text/plain格式器以支持提交string类型的httpbody
                options.InputFormatters.Add(new TextPlainInputFormatter());
                //输出日期类型为iso标准
                var jsonOutputFormatter = new JsonOutputFormatter
                {
                    SerializerSettings =
                    {
                        ContractResolver =new CamelCasePropertyNamesContractResolver(),
                        DefaultValueHandling = DefaultValueHandling.Ignore,
                        DateFormatHandling=DateFormatHandling.IsoDateFormat
                    }
                };
                options.OutputFormatters.RemoveType<JsonOutputFormatter>();
                options.OutputFormatters.Insert(0, jsonOutputFormatter);
            });
            services.AddCors();
            services.AddInstance<IConfiguration>(Configuration);
        }

        ConcurrentDictionary<string, WebSocket> _sockets = new ConcurrentDictionary<string, WebSocket>();
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();

            app.UseIISPlatformHandler();

            ////IP地址访问限制/配置于appsettings.json,不配置将允许所有访问请求
            //app.UseMiddleware<middleware.CheckIPMiddleware>();

            ////使用压缩技术响应请求
            //app.UseMiddleware<middleware.CompressionMiddleware>();

            app.UseStaticFiles();

            app.UseWebSockets();
            app.Use(async (http, next) =>
            {
                if (http.WebSockets.IsWebSocketRequest)
                {
                    var webSocket = await http.WebSockets.AcceptWebSocketAsync();
                    if (webSocket != null && webSocket.State == WebSocketState.Open)
                    {
                        if (_sockets.TryAdd(Guid.NewGuid().ToString("n"), webSocket))
                        {
                            await Task.Run(async () => {
                                while (webSocket.State == WebSocketState.Open)
                                {
                                    var token = CancellationToken.None;
                                    var buffer = new ArraySegment<Byte>(new Byte[4096]);

                                    // Below will wait for a request message.
                                    var received = await webSocket.ReceiveAsync(buffer, token);

                                    switch (received.MessageType)
                                    {
                                        case WebSocketMessageType.Text:
                                            var request = Encoding.UTF8.GetString(buffer.Array, buffer.Offset, buffer.Count);
                                            //var data = Encoding.UTF8.GetBytes(text);
                                            //var buffer = new ArraySegment<Byte>(data);
                                            var SendBuffer = new ArraySegment<byte>(buffer.Array, 0, received.Count);
                                            await Task.WhenAll(_sockets.Where(ws=> ws.Value.State == WebSocketState.Open)
                                                .Select(s => s.Value.SendAsync(SendBuffer, WebSocketMessageType.Text, true, CancellationToken.None)));
                                            break;
                                    }
                                }
                            });
                        }
                    }
                }
                else
                {
                    // Nothing to do here, pass downstream.  
                    await next();
                }
            });

            app.UseMvc();
        }

        // Entry point for the application.
        public static void Main(string[] args) => WebApplication.Run<Startup>(args);
    }
}
